﻿using CaroLibraly;
using System.Drawing;

namespace CaroLibrary
{
    /// <summary>
    /// Bàn cờ. Để lưu trạng thái bàn cờ, kiểm tra xem quân nào thắng
    /// </summary>
    public class Board
    {
        #region Thuộc tính của bàn cờ
        /// <summary>
        /// 2 chiều
        /// </summary>
        public char[,] Cells { get; set; }
        /// <summary>
        /// Max(Số hàng, số cột) của bàn cờ
        /// </summary>
        public int NumberLines { get; private set; }
        /// <summary>
        /// Kích thước của một ô cờ
        /// </summary>
        public int CellSize { get; private set; }
        /// <summary>
        /// Chứa dữ liệu cửa lượt chơi hiện tại
        /// </summary>
        public Turn CurrentTurn { get; private set; }
        public char PlayerSymbol { set; get; }
        #endregion

        #region Khởi tạo
        public Board()
        {
            this.Cells = new char[20, 20];
            this.CurrentTurn = new Turn();
        }

        public Board(int _numberlines, int _cellsize)
        {
            this.CellSize = _cellsize;
            this.NumberLines = _numberlines;
            this.Cells = new char[_numberlines + 2, _numberlines + 2];
            for (int i = 0; i < _numberlines + 2; i++)
                for (int j = 0; j < _numberlines + 2; j++)
                    this.Cells[i, j] = ' ';
            this.CurrentTurn = new Turn();
        }
        #endregion

        #region Các hàm, thủ tục
        #region Phương thức
        public Board Clone()
        {
            Board b = new Board(this.NumberLines, this.CellSize);
            for (int i = 0; i <= this.NumberLines; i++)
                for (int j = 0; j <= this.NumberLines; j++)
                    b.Cells[i, j] = this.Cells[i, j];
            return b;
        }
        public bool CheckPosition(int x, int y)
        {
            return (x >= 0 && y >= 0 && x < this.CellSize && y < this.CellSize);
        }
        #endregion

        #region Get, set
        /// <summary>
        /// Nạp quân cờ vào 1 ô
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="c"></param>
        public void SetCell(int x, int y, char c)
        {
            this.Cells[x, y] = c;
            this.CurrentTurn.SetTurn(x, y, c);
        }

        /// <summary>
        /// Lấy quân cờ của 1 ô
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        public char GetCell(int x, int y)
        {
            try
            {
                return this.Cells[x, y];
            }
            catch
            {
                return ' ';
            }
        }

        private int GetVal(int n)
        {
            if (n < 0)
                return 1;
            if (n > this.NumberLines)
                return this.NumberLines;
            return n;
        }
        #endregion

        #region Kiểm tra thắng trận
        /// <summary>
        /// Kiểm tra hàng dọc
        /// </summary>
        /// <param name="x">Tọa độ x</param>
        /// <param name="y">Tọa độ y</param>
        /// <param name="c">o-x</param>
        /// <returns></returns>
        private Line Check1(int x, int y, char c)
        {
            Line l = new Line();
            int px = (x - 1) * this.CellSize + this.CellSize / 2;//Tọa độ x. Cố định luôn, chỉ cẩn tính tọa độ y thôi
            //Đi ngược lên trên để kiểm tra
            while (this.Cells[x, y] == c && y > 0)
                y--;
            //Đi từ điểm trên nhất xem đủ 5 ô chưa?
            int count = 0;
            l.Start = new Point(px, ++y * this.CellSize + this.CellSize / 2);
            while (this.Cells[x, y] == c && y <= this.NumberLines)
            {
                y++;
                count++;
            }
            l.End = new Point(px, y * this.CellSize - this.CellSize / 2);
            if (count >= 5)
                l.Win = true;
            return l;
        }

        /// <summary>
        /// Kiểm tra hàng ngang
        /// </summary>
        /// <param name="x">Tọa độ x</param>
        /// <param name="y">Tọa độ y</param>
        /// <param name="c">o-x</param>
        /// <returns></returns>
        private Line Check2(int x, int y, char c)
        {
            Line l = new Line();
            int py = y * this.CellSize + this.CellSize/2;//Tọa độ y. Cố định luôn, chỉ cẩn tính tọa độ x thôi
            //Đi sang trái
            while (this.Cells[x, y] == c && y > 0)
                x--;
            //Đi từ điểm trái nhất xem đủ 5 ô chưa?
            int count = 0;
            l.Start = new Point(x++ * this.CellSize + this.CellSize / 2, py);
            while (this.Cells[x, y] == c && y <= this.NumberLines)
            {
                x++;
                count++;
            }
            l.End = new Point((x - 2) * this.CellSize + this.CellSize / 2, py);
            if (count >= 5)
                l.Win = true;
            return l;
        }

        /// <summary>
        /// Kiểm tra đường chéo chính
        /// </summary>
        /// <param name="x">Tọa độ x</param>
        /// <param name="y">Tọa độ y</param>
        /// <param name="c">o-x</param>
        /// <returns></returns>
        private Line Check3(int x, int y, char c)
        {
            Line l = new Line();
            //Đi sang trái
            while (this.Cells[x, y] == c && y > 0)
            {
                x--;
                y--;
            }
            //Đi từ điểm trái nhất xem đủ 5 ô chưa?
            int count = 0;
            l.Start = new Point((x++ + 1) * this.CellSize - this.CellSize / 2, (y++ + 1) * this.CellSize + this.CellSize / 2);
            while (this.Cells[x, y] == c && y <= this.NumberLines)
            {
                x++;
                y++;
                count++;
            }
            x--; y--;
            l.End = new Point(x * this.CellSize - this.CellSize / 2, y * this.CellSize + this.CellSize / 2);
            if (count >= 5)
                l.Win = true;
            return l;
        }

        /// <summary>
        /// Kiểm tra đường chéo phụ
        /// </summary>
        /// <param name="x">Tọa độ x</param>
        /// <param name="y">Tọa độ y</param>
        /// <param name="c">o-x</param>
        /// <returns></returns>
        private Line Check4(int x, int y, char c)
        {
            Line l = new Line();
            //Đi sang trái
            while (this.Cells[x, y] == c && y > 0)
            {
                x++;
                y--;
            }
            //Đi từ điểm trái nhất xem đủ 5 ô chưa?
            int count = 0;
            l.Start = new Point((x-- - 1) * this.CellSize - this.CellSize / 2, (y++ + 1) * this.CellSize + this.CellSize / 2);
            x = this.GetVal(x);
            y = this.GetVal(y);
            while (this.Cells[x, y] == c && y <= this.NumberLines)
            {
                x--;
                y++;
                count++;
            }
            x++; y--;
            l.End = new Point(x * this.CellSize - this.CellSize / 2, y * this.CellSize + this.CellSize / 2);
            if (count >= 5)
                l.Win = true;
            return l;
        }

        /// <summary>
        /// Kiểm tra xem có người thắng chưa?
        /// </summary>
        /// <param name="x">Tọa độ x</param>
        /// <param name="y">Tọa độ y</param>
        /// <param name="c">o-x</param>
        /// <returns></returns>
        private Line CheckWin(int x, int y, char c)
        {
            Line l = new Line();
            if (c == ' ' || c == '\0')
                return l;
            l = Check1(x, y, c);
            if (l.Win)
                return l;
            l = Check2(x, y, c);
            if (l.Win)
                return l;
            l = Check3(x, y, c);
            if (l.Win)
                return l;
            l = Check4(x, y, c);
            if (l.Win)
                return l;
            return l;
        }

        /// <summary>
        /// Kiểm tra xem 1 turn có thắng hay không
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        public Line CheckWin(Turn t)
        {
            return this.CheckWin(t.CellX, t.CellY, t.Game);
        }

        /// <summary>
        /// Kiểm tra xem lượt chơi hiện tại (this.Turn) có làm một trong 2 thắng hay không
        /// </summary>
        /// <returns></returns>
        public Line CheckWin()
        {
            return this.CheckWin(this.CurrentTurn);
        }
        #endregion
        #endregion
    }
}